import pandas as pd
from openpyxl import load_workbook
from tqdm import tqdm
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.io as pio
import warnings
import os
import numpy as np

# 忽略警告
warnings.filterwarnings('ignore')


def read_large_excel(file_path, time_col, value_cols, max_rows=150000):
    """高效读取大型Excel文件"""
    wb = load_workbook(filename=file_path, read_only=True)
    ws = wb.active

    # 获取列索引
    header = next(ws.values)
    col_idx = {name: idx for idx, name in enumerate(header)}

    data = []
    for row in tqdm(ws.iter_rows(min_row=2, values_only=True), total=max_rows):
        if len(data) >= max_rows:
            break
        try:
            time_val = pd.to_datetime(row[col_idx[time_col]])
            values = [float(row[col_idx[col]]) if row[col_idx[col]] is not None else None
                      for col in value_cols]
            data.append([time_val] + values)
        except (ValueError, TypeError) as e:
            continue

    columns = [time_col] + value_cols
    return pd.DataFrame(data, columns=columns)


def get_valid_excel_path():
    """获取有效的Excel文件路径"""
    while True:
        file_path = input("请输入Excel文件完整路径（或拖拽文件到此处）: ").strip('"')

        # 检查文件是否存在
        if not os.path.exists(file_path):
            print(f"错误：文件 '{file_path}' 不存在，请重新输入")
            continue

        # 检查文件扩展名
        if not file_path.lower().endswith(('.xlsx', '.xls')):
            print("错误：仅支持.xlsx或.xls格式的Excel文件")
            continue

        return file_path


def get_valid_frequency():
    """获取有效的采样频率"""
    freq_options = {
        '1': '1T',  # 1分钟
        '2': '5T',  # 5分钟
        '3': '1H',  # 1小时
        '4': '1D',  # 1天
        '5': '7D',  # 7天
        '6': '30D',  # 30天
        '7': '1S'  # 1秒
    }

    while True:
        print("\n请选择展示维度：")
        print("1. 1分钟   2. 5分钟")
        print("3. 1小时   4. 1天")
        print("5. 7天     6. 30天")
        print("7. 1秒")
        choice = input("请输入选项编号(1-6，默认4): ").strip()

        if not choice:
            return '1D'  # 默认1天

        if choice in freq_options:
            return freq_options[choice]

        print("错误：请输入1-6之间的有效编号")


def export_html(fig, excel_file_path, freq):
    """安全导出HTML文件"""
    try:
        base_name = os.path.splitext(os.path.basename(excel_file_path))[0]
        safe_name = "".join(c for c in base_name if c.isalnum() or c in (' ', '_', '-')).strip()
        html_file = f"{safe_name}_{freq}.html"

        # 创建输出目录
        output_dir = os.path.abspath("output")
        os.makedirs(output_dir, exist_ok=True)
        full_path = os.path.join(output_dir, html_file)

        # 简化HTML配置
        config = {
            'responsive': True,
            'displayModeBar': True,
            'scrollZoom': True
        }

        # 写入HTML（使用本地plotly.js）
        pio.write_html(
            fig,
            file=full_path,
            config=config,
            auto_open=False,
            include_plotlyjs='cdn',  # 可改为'directory'使用本地文件
            full_html=True,
            default_width='100%',
            default_height='90vh'
        )

        print(f"\nHTML文件已保存到：{full_path}")
        print("提示：如果浏览器无法打开，请尝试：")
        print("1. 使用Chrome/Firefox浏览器")
        print("2. 右键文件 → 选择打开方式 → 选择浏览器")

        return full_path

    except Exception as e:
        print(f"导出HTML失败：{str(e)}")
        # 尝试保存为图片
        try:
            img_path = os.path.join(output_dir, f"{safe_name}.png")
            fig.write_image(img_path, scale=2)
            print(f"已转为PNG图片保存到：{img_path}")
            return img_path
        except:
            print("无法保存为图片，请检查plotly-orca安装")
            return None


def main():
    print("=== Excel数据可视化工具 ===")
    print("请确保Excel文件包含以下列：")
    print("- 时间列：'cjsj:采集时间'")
    print("- 数值列：'jkhy:井口回压', 'jkwd:井口温度', 'zzzh:最大载荷', 'zxzh:最小载荷'")
    print("=" * 30)

    # 获取文件路径
    excel_file = get_valid_excel_path()

    # 获取展示频率
    freq = get_valid_frequency()

    try:
        # 固定配置（可根据需要修改）
        #time_column = 'cjsj:采集时间'
        #value_columns = ['jkhy:井口回压', 'jkwd:井口温度', 'zzzh:最大载荷', 'zxzh:最小载荷']
        #colors = ['#8B4513', '#FF4500', '#3CB371', '#1E90FF']
        time_column = '时间'
        #value_columns = ['兴华1-135X_回压', '兴华1-135X_加热杆设定温度', '兴华1-135X_电机运行状态', '兴华1-135X_加热杆耗电量','兴华1-135X_井口油温','兴华1-135X_电机有功功耗']
        #value_columns = ['兴华1-50X_回压', '兴华1-50X_加热杆设定温度', '兴华1-50X_电机运行状态', '兴华1-50X_加热杆耗电量','兴华1-50X_井口油温','兴华1-50X_电机有功功耗']
        #value_columns = ['兴华1-135X_电机运行状态','兴华1-135X_加热杆设定温度','兴华1-135X_井口油温','兴华1-135X_回压',
        #                '兴华1-135X_电机有功功耗','兴华1-135X_加热杆耗电量','兴华1-135X_电机日耗电量','兴华1-135X_加热杆日耗电量']
        value_columns = ['兴华1-50X_电机运行状态','兴华1-50X_加热杆设定温度','兴华1-50X_井口油温','兴华1-50X_回压','兴华1-50X_电机有功功耗','兴华1-50X_加热杆耗电量','兴华1-50X_电机日耗电量功功耗','兴华1-50X_加热杆日耗电量']
        colors = ["#061F74", '#FF4500', '#3CB371', '#1E90FF', "#04294E", "#2DDD85", "#1E2220", "#8F1F5E"]
        print(f"\n正在读取Excel文件: {excel_file}")
        df = read_large_excel(excel_file, time_column, value_columns)

        # 数据处理
        print("\n数据处理中...")
        df = df.sort_values(time_column).set_index(time_column)

        # 智能降采样
        time_span = df.index[-1] - df.index[0]
        # if time_span > pd.Timedelta(days=365):
        #     freq = '7D'  # 每周
        # elif time_span > pd.Timedelta(days=30):
        #     freq = '1D'  # 每天
        # elif time_span > pd.Timedelta(days=1):
        #     freq = '1H'  # 每小时
        # else:
        #     freq = '5T'  # 5分钟
        # freq = '1D'  # 默认1天
        # 'D'（按天）
        # 'W'（按周）
        # 'M'（按月）
        # 'H'（按小时）
        # '5T'（每5分钟）

        #  对比不同聚合方法
        # .mean() 计算区间均值
        # .max() 计算区间最大值
        # .min() 计算区间最小值
        # .sum() 计算区间求和\
        # .first() 取区间第一个值
        # .last() 取区间最后一个值
        #print(f"\n时间跨度: {time_span}, 使用展示维度: {freq}")
        #mean() 对每个时间区间内的数据 计算平均值（例如，1把每日数据聚合成每月均值）
        #ffill() 前向填充（Forward Fill），用前一个有效值填充后面的 NaN。
        #.replace(-999999, np.nan) 过滤异常值
        #遇到excel中是计算公式算出的值，导致页面不显示。可以把计算出的值重新赋值给对应的列
        #resampled = df.replace(-999999, np.nan).resample(freq).mean().ffill()  #带智能降采样
        resampled = df.replace(-999999, np.nan).ffill()  #去掉智能降采样
        print(f"数据点从 {len(df)} 减少到 {len(resampled)}")

        # 创建图表
        print("\n生成图表中...")
        fig = make_subplots(specs=[[{"secondary_y": True}]])

        # 为每个指标添加曲线
        for idx, col in enumerate(value_columns):
            fig.add_trace(
                go.Scattergl(
                    x=resampled.index,
                    y=resampled[col],
                    name=col, #col.split(':')[1],
                    mode='lines',
                    line=dict(width=1.5, color=colors[idx]),
                    opacity=0.9,
                    # 悬停时显示完整列名和数值
                    hovertemplate=(
                        f"<b>{col}</b><br>"  # 显示完整列名
                        #"时间: %{x|%Y-%m-%d %H:%M:%S}<br>"
                        "数值: %{y:.2f}<extra></extra>"
                    )
                ),
                secondary_y=False
            )

        # 更新图表布局
        fig.update_layout(
            title=dict(text=f'{os.path.basename(excel_file)}数据分析', x=0.5, xanchor='center'),
            xaxis_title='采集时间',
            yaxis_title='数值',
            height=700,
            template='plotly_white',
            hovermode="x unified",
            legend=dict(
                orientation="h",
                yanchor="bottom",
                y=1.02,
                xanchor="right",
                x=1
            ),
            margin=dict(l=50, r=50, b=50, t=80, pad=4),
            # 设置固定间隔显示
            # xaxis = dict(
            #     rangeslider=dict(
            #         visible=True,
            #         thickness=0.1
            #     ),
            #     # 固定显示30个数据点
            #     range=[resampled.index[0], resampled.index[min(30, len(resampled) - 1)]]
            # )
        )

        # 更新X轴设置
        fig.update_xaxes(
            tickformat="%Y-%m-%d %H:%M:%S",
            rangeslider_visible=True,
            rangeselector=dict(
                # buttons=list([
                #     dict(count=5, label="5分钟", step="minute", stepmode="backward"),
                #     dict(count=1, label="1小时", step="hour", stepmode="backward"),
                #     dict(count=1, label="1天", step="day", stepmode="backward"),
                #     dict(count=7, label="1周", step="day", stepmode="backward"),
                #     dict(count=1, label="1月", step="month", stepmode="backward"),
                #     dict(step="all", label="全部数据")
                # ])
                #bgcolor='lightgray'
            ),
            # 固定间隔显示
            #tickmode='auto',
            #nticks=15  # 控制显示的刻度数量
        )
        print("\n图表生成完成！将在浏览器中打开...")
        fig.show()

        # 询问是否导出HTML
        export = input("\n是否导出为HTML文件？(y/n, 默认y): ").strip().lower() or 'y'
        if export == 'y':
            html_path = export_html(fig, excel_file, freq)
            print(f"\nHTML报告已保存到: {html_path}")
            print("提示：HTML文件保留了所有交互功能，可以用浏览器直接打开")

    except Exception as e:
        print(f"\n发生错误: {str(e)}")
        input("按Enter键退出...")


#pyinstaller.exe --onefile -c -n 巴彦现场数据分析工具 -i D:\富岛\pythonWorkspace\oilTemperatureTrend\dist\images\logo.ico  main.py
if __name__ == "__main__":
    main()
    input("\n操作完成，按Enter键退出程序...")